﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using CarbonExchange.Bll;

namespace CarbonExchange.Tests
{
    [TestClass]
    public class EmailRestrictionTests : BaseTest
    {
        [TestMethod]
        public void EmailRestriction_GetAllBySiteId_WithIncorrectSiteId_ReturnsEmptyList()
        {
            Bll.EmailRestrictionFactory factory = new CarbonExchange.Bll.EmailRestrictionFactory(_Context);
            Assert.AreEqual(0, factory.GetAllBySiteId(int.MaxValue).Count());
        }

        [TestMethod]
        public void EmailRestriction_GetAllBySiteId_WithCorrectSiteId_ReturnsList()
        {
            Bll.EmailRestrictionFactory factory = new CarbonExchange.Bll.EmailRestrictionFactory(_Context);
            Assert.AreEqual(4, factory.GetAllBySiteId(_TestSite.Id).Count());
        }

        [TestMethod]
        public void EmailRestriction_GetById_WithIncorrectId_ReturnsNull()
        {
            Bll.EmailRestrictionFactory factory = new CarbonExchange.Bll.EmailRestrictionFactory(_Context);
            Assert.IsNull(factory.GetById(int.MaxValue));
        }

        [TestMethod]
        public void EmailRestriction_GetById_WithCorrectId_ReturnsNotNull()
        {
            Bll.EmailRestrictionFactory factory = new CarbonExchange.Bll.EmailRestrictionFactory(_Context);
            Assert.IsNotNull(factory.GetById(_TestEmailRestrictions[0].Id));
        }

        [TestMethod]
        public void EmailRestriction_GetAllBySiteId_WithCorrectId_PopulatesCorrectProperties()
        {
            Bll.EmailRestrictionFactory factory = new CarbonExchange.Bll.EmailRestrictionFactory(_Context);
            var tmp = factory.GetAllBySiteId(_TestSite.Id);
            Assert.AreEqual(4, tmp.Count());
            var tmpItem = tmp.ToArray().OrderBy(x => x.Id).ToArray()[0];
            Assert.AreEqual(_TestEmailRestrictions[0].Id, tmpItem.Id);
            Assert.AreEqual("allow@mann.com", tmpItem.EmailFilter);
            Assert.AreEqual(_TestSite.Id, tmpItem.SiteId);
            Assert.AreEqual(DateTime.Parse("24/10/1975 12:00:00"), tmpItem.Created);
        }

        [TestMethod]
        public void EmailRestriction_GetById_WithCorrectId_PopulatesCorrectProperties()
        {
            Bll.EmailRestrictionFactory factory = new CarbonExchange.Bll.EmailRestrictionFactory(_Context);
            var tmpItem = factory.GetById(_TestEmailRestrictions[0].Id);
            Assert.IsNotNull(tmpItem);
            Assert.AreEqual(_TestEmailRestrictions[0].Id, tmpItem.Id);
            Assert.AreEqual("allow@mann.com", tmpItem.EmailFilter);
            Assert.AreEqual(_TestSite.Id, tmpItem.SiteId);
            Assert.AreEqual(DateTime.Parse("24/10/1975 12:00:00"), tmpItem.Created);
        }

        [TestMethod]
        public void EmailRestriction_InsertOne()
        {
            Bll.EmailRestrictionFactory factory = new CarbonExchange.Bll.EmailRestrictionFactory(_Context);
            Bll.EmailRestriction tmp = new CarbonExchange.Bll.EmailRestriction(_TestSite.Id);
            tmp.EmailFilter = "Insert_Test";

            DateTime expected = DateTime.Now;
            factory.Save(tmp);

            Assert.IsTrue(tmp.Id > 0);
            Assert.AreEqual(_TestSite.Id, tmp.SiteId);
            Assert.AreEqual("Insert_Test", tmp.EmailFilter);
            Assert.IsTrue(TimeSpan.FromSeconds(1) > (tmp.Created - expected));

            Bll.EmailRestriction tmp2 = factory.GetById(tmp.Id);
            Assert.AreEqual(tmp.Id, tmp2.Id);
            Assert.AreEqual(tmp.SiteId, tmp2.SiteId);
            Assert.AreEqual(tmp.EmailFilter, tmp2.EmailFilter);
            Assert.AreEqual(tmp.Created, tmp2.Created);
        }

        [TestMethod]
        public void EmailRestriction_InsertMany()
        {
            Bll.EmailRestrictionFactory factory = new CarbonExchange.Bll.EmailRestrictionFactory(_Context);

            int loopCount = 5;
            int existingCount = factory.GetAllBySiteId(_AlternateSite.Id).Count();
            List<Bll.EmailRestriction> updates = new List<Bll.EmailRestriction>();
            for (int i = 0; i < loopCount; i++)
            {
                Bll.EmailRestriction item = new Bll.EmailRestriction(_AlternateSite.Id);
                item.EmailFilter = string.Format("zInsert Test {0}", i);
                updates.Add(item);
            }

            DateTime expectedDateTime = DateTime.Now;
            factory.Save(updates.AsQueryable());

            int[] tmpIds = new int[loopCount];
            for (int i = 0; i < loopCount; i++)
            {
                tmpIds[i] = updates[i].Id;
                Assert.IsTrue(updates[i].Id > 0);
                Assert.AreEqual(_AlternateSite.Id, updates[i].SiteId);
                Assert.AreEqual(string.Format("zInsert Test {0}", i), updates[i].EmailFilter);
                Assert.AreEqual(expectedDateTime.ToLongDateString(), updates[i].Created.ToLongDateString());
                Assert.AreEqual(expectedDateTime.ToLongTimeString(), updates[i].Created.ToLongTimeString());
            }

            var saved = factory.GetAllBySiteId(_AlternateSite.Id).Skip(existingCount).ToArray();
            Assert.AreEqual(loopCount, saved.Count());
            for (int i = 0; i < saved.Count(); i++)
            {
                Assert.AreEqual(tmpIds[i], saved[i].Id);
                Assert.AreEqual(_AlternateSite.Id, saved[i].SiteId);
                Assert.AreEqual(string.Format("zInsert Test {0}", i), saved[i].EmailFilter);
                Assert.AreEqual(expectedDateTime.ToLongDateString(), saved[i].Created.ToLongDateString());
                Assert.AreEqual(expectedDateTime.ToLongTimeString(), saved[i].Created.ToLongTimeString());
            }
        }

        [TestMethod]
        public void EmailRestriction_UpdateOne()
        {
            Bll.EmailRestrictionFactory factory = new Bll.EmailRestrictionFactory(_Context);
            var tmp = factory.GetById(_TestEmailRestrictions[0].Id);
            tmp.EmailFilter = "Update Test";
            factory.Save(tmp);
            Assert.AreEqual("Update Test", tmp.EmailFilter);
            tmp = factory.GetById(_TestEmailRestrictions[0].Id);
            Assert.AreEqual("Update Test", tmp.EmailFilter);
        }

        [TestMethod]
        public void EmailRestriction_UpdateMany()
        {
            Bll.EmailRestrictionFactory factory = new Bll.EmailRestrictionFactory(_Context);
            var tmp = factory.GetAllBySiteId(_TestSite.Id).ToArray();
            for (int i = 0; i < tmp.Count(); i++)
            {
                tmp.ElementAt(i).EmailFilter = string.Format("Update Test {0}", i);
            }
            factory.Save(tmp.AsQueryable());
            for (int i = 0; i < tmp.Count(); i++)
            {
                Assert.AreEqual(string.Format("Update Test {0}", i), tmp.ElementAt(i).EmailFilter);
            }
            tmp = factory.GetAllBySiteId(_TestSite.Id).ToArray();
            for (int i = 0; i < tmp.Count(); i++)
            {
                Assert.AreEqual(string.Format("Update Test {0}", i), tmp.ElementAt(i).EmailFilter);
            }
        }

        [TestMethod]
        public void EmailRestriction_DeleteOne()
        {
            Bll.EmailRestrictionFactory factory = new Bll.EmailRestrictionFactory(_Context);
            var item = factory.GetById(_TestEmailRestrictions[0].Id);
            Assert.IsNotNull(item);
            factory.Delete(item);
            Assert.AreEqual(3, factory.GetAllBySiteId(_TestSite.Id).Count());
            item = factory.GetById(_TestEmailRestrictions[0].Id);
            Assert.IsNull(item);
        }

        [TestMethod]
        public void EmailRestriction_DeleteMany()
        {
            Bll.EmailRestrictionFactory factory = new Bll.EmailRestrictionFactory(_Context);
            var items = factory.GetAllBySiteId(_TestSite.Id);
            Assert.IsTrue(items.Count() > 1);
            factory.Delete(items);
            items = factory.GetAllBySiteId(_TestSite.Id);
            Assert.AreEqual(0, items.Count());
        }

        [TestMethod]
        public void EmailRestriction_ValidateWithRealEmail_AccessReturnsAllowed()
        {
            var tmp = new Bll.EmailRestriction(_TestSite.Id);

            tmp.Access = true;
            tmp.EmailFilter = @"^([0-9a-zA-Z]([-.\w]*[0-9a-zA-Z+])*@([0-9a-zA-Z][-\w]*[0-9a-zA-Z]\.)+[a-zA-Z]{2,9})$";

            Assert.AreEqual(CarbonExchange.Bll.EmailRestriction.ValidationResult.Allowed, tmp.ValidateEmail("test@test.com"));
        }

        [TestMethod]
        public void EmailRestriction_ValidateWithRealEmail_NoAccessReturnsRefused()
        {
            var tmp = new Bll.EmailRestriction(_TestSite.Id);

            tmp.Access = false;
            tmp.EmailFilter = @"^([0-9a-zA-Z]([-.\w]*[0-9a-zA-Z+])*@([0-9a-zA-Z][-\w]*[0-9a-zA-Z]\.)+[a-zA-Z]{2,9})$";

            Assert.AreEqual(CarbonExchange.Bll.EmailRestriction.ValidationResult.Refused, tmp.ValidateEmail("test@test.com"));
        }

        [TestMethod]
        public void EmailRestriction_ValidateWithFakeEmail_ReturnsNull()
        {
            var tmp = new Bll.EmailRestriction(_TestSite.Id);

            tmp.EmailFilter = @"^([0-9a-zA-Z]([-.\w]*[0-9a-zA-Z+])*@([0-9a-zA-Z][-\w]*[0-9a-zA-Z]\.)+[a-zA-Z]{2,9})$";

            Assert.AreEqual(CarbonExchange.Bll.EmailRestriction.ValidationResult.NotFound, tmp.ValidateEmail("test.com"));
        }

        [TestMethod]
        public void EmailRestriction_ValidateManyWithRealEmail_ReturnsTrueWhenAllowed()
        {
            var tmp = new Bll.EmailRestrictionFactory(_Context);
            var items = new Bll.EmailRestriction[3];

            items[0] = new CarbonExchange.Bll.EmailRestriction(_TestSite.Id);
            items[0].EmailFilter = "rubbish";
            items[0].Access = false;

            items[1] = new CarbonExchange.Bll.EmailRestriction(_TestSite.Id);
            items[1].EmailFilter = @"^([0-9a-zA-Z]([-.\w]*[0-9a-zA-Z+])*@([0-9a-zA-Z][-\w]*[0-9a-zA-Z]\.)+[a-zA-Z]{2,9})$";
            items[1].Access = true;
            
            items[2] = new CarbonExchange.Bll.EmailRestriction(_TestSite.Id);
            items[2].EmailFilter = @"test@test.com";
            items[2].Access = true;

            Assert.IsTrue(tmp.ValidateEmail("test@test.com", items.AsQueryable()));
        }

        [TestMethod]
        public void EmailRestriction_ValidateManyWithRealEmail_ReturnsFalseWhenNotAllowed()
        {
            var tmp = new Bll.EmailRestrictionFactory(_Context);
            var items = new Bll.EmailRestriction[3];

            items[0] = new CarbonExchange.Bll.EmailRestriction(_TestSite.Id);
            items[0].EmailFilter = "rubbish";
            items[0].Access = false;

            items[1] = new CarbonExchange.Bll.EmailRestriction(_TestSite.Id);
            items[1].EmailFilter = @"^([0-9a-zA-Z]([-.\w]*[0-9a-zA-Z+])*@([0-9a-zA-Z][-\w]*[0-9a-zA-Z]\.)+[a-zA-Z]{2,9})$";
            items[1].Access = true;

            items[2] = new CarbonExchange.Bll.EmailRestriction(_TestSite.Id);
            items[2].EmailFilter = @"test@test.com";
            items[2].Access = false;

            Assert.IsFalse(tmp.ValidateEmail("test@test.com", items.AsQueryable()));
        }

        [TestMethod]
        public void EmailRestriction_ValidateManyWithFakeEmail_ReturnsFalse()
        {
            var tmp = new Bll.EmailRestrictionFactory(_Context);
            var items = tmp.GetAllBySiteId(_TestSite.Id);
            Assert.IsFalse(tmp.ValidateEmail("test.com", items));
        }

        [TestMethod]
        public void EmailRestriction_GetAllByUserId_ReturnsCorrectList()
        {
            var factory = new Bll.EmailRestrictionFactory(_Context);
            var tmp = factory.GetAllByUserId(_TestUsers[0].Id);
            Assert.AreEqual(4, tmp.Count());
        }

        [TestMethod]
        public void EmailRestriction_ValidateWithExactMatch_ReturnsExpectedResults()
        {
            var tmp = new EmailRestriction(_AlternateSite.Id);
            tmp.EmailFilter = "test@email.com";
            tmp.Access = true;
            Assert.AreEqual(EmailRestriction.ValidationResult.Allowed, tmp.ValidateEmail("test@email.com"));
            Assert.AreEqual(EmailRestriction.ValidationResult.NotFound, tmp.ValidateEmail("test@email_com"));

            tmp.Access = false;
            Assert.AreEqual(EmailRestriction.ValidationResult.Refused, tmp.ValidateEmail("test@email.com"));
            
            Assert.AreEqual(EmailRestriction.ValidationResult.NotFound, tmp.ValidateEmail("test@email2.com"));
            Assert.AreEqual(EmailRestriction.ValidationResult.NotFound, tmp.ValidateEmail("2test@email.com"));
            Assert.AreEqual(EmailRestriction.ValidationResult.NotFound, tmp.ValidateEmail("testing@email.com"));

        }

        [TestMethod]
        public void EmailRestriction_ValidateWithStartingStar_ReturnsExpectedResults()
        {
            var tmp = new EmailRestriction(_AlternateSite.Id);
            tmp.EmailFilter = "*@email.com";
            tmp.Access = true;

            Assert.AreEqual(EmailRestriction.ValidationResult.Allowed, tmp.ValidateEmail("test@email.com"));
            Assert.AreEqual(EmailRestriction.ValidationResult.Allowed, tmp.ValidateEmail("anothertesting@email.com"));
            Assert.AreEqual(EmailRestriction.ValidationResult.NotFound, tmp.ValidateEmail("@email.com"));
            Assert.AreEqual(EmailRestriction.ValidationResult.NotFound, tmp.ValidateEmail("test@email_com"));
            Assert.AreEqual(EmailRestriction.ValidationResult.NotFound, tmp.ValidateEmail("test@email.coms"));

        }

        [TestMethod]
        public void EmailRestriction_ValidateWithEndingStar_ReturnsExpectedResults()
        {
            var tmp = new EmailRestriction(_AlternateSite.Id);
            tmp.EmailFilter = "test@email.*";
            tmp.Access = true;

            Assert.AreEqual(EmailRestriction.ValidationResult.Allowed, tmp.ValidateEmail("test@email.com"));
            Assert.AreEqual(EmailRestriction.ValidationResult.Allowed, tmp.ValidateEmail("test@email.co.uk"));
            Assert.AreEqual(EmailRestriction.ValidationResult.NotFound, tmp.ValidateEmail("@email.com"));
            Assert.AreEqual(EmailRestriction.ValidationResult.NotFound, tmp.ValidateEmail("stilltest@email.com"));
            Assert.AreEqual(EmailRestriction.ValidationResult.NotFound, tmp.ValidateEmail("test@email_coms"));

        }


        [TestMethod]
        public void EmailRestriction_ValidateWithStarInMiddle_ReturnsExpectedResults()
        {

            var tmp = new EmailRestriction(_AlternateSite.Id);

            tmp.EmailFilter = "musthave*@email.com";
            tmp.Access = true;
            Assert.AreEqual(EmailRestriction.ValidationResult.Allowed, tmp.ValidateEmail("musthave_test_@email.com"));
            Assert.AreEqual(EmailRestriction.ValidationResult.NotFound, tmp.ValidateEmail("test@email.com"));
            Assert.AreEqual(EmailRestriction.ValidationResult.NotFound, tmp.ValidateEmail("no_musthave_test_@email.com"));
            Assert.AreEqual(EmailRestriction.ValidationResult.NotFound, tmp.ValidateEmail("musthave_test_@email.co.uk"));

        }

        [TestMethod]
        public void EmailRestriction_ValidateMultipleStars_ReturnsExpectedResults()
        {

            var tmp = new EmailRestriction(_AlternateSite.Id);

            tmp.EmailFilter = "*test*@*email.*";
            tmp.Access = true;
            Assert.AreEqual(EmailRestriction.ValidationResult.Allowed, tmp.ValidateEmail("_test_@_email._"));
            Assert.AreEqual(EmailRestriction.ValidationResult.NotFound, tmp.ValidateEmail("test_@_email._"));
            Assert.AreEqual(EmailRestriction.ValidationResult.NotFound, tmp.ValidateEmail("_test@_email._"));
            Assert.AreEqual(EmailRestriction.ValidationResult.NotFound, tmp.ValidateEmail("_test_@email._"));
            Assert.AreEqual(EmailRestriction.ValidationResult.NotFound, tmp.ValidateEmail("_test_@_email."));

        }
    }
}
